#ifndef LOGGER_H
#define LOGGER_H
/* 
 * File:   logger.cpp
 * Author: stas
 *
 * Created on 14 Март 2013 г., 14:19
 */
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <time.h>

#include <string.h>

#define MAX_BUFFER_SIZE 2
#define FILE_LOG "log.txt"

using namespace std;

char **my_get_time(){
    //Возвращает время в нужном формате
    time_t *t = new time_t;
    time(t);
    char *year = new char[20];
    char *time = new char[20];
    strftime(year, 100, "%Y-%m-%d", localtime(t));
    strftime(time, 100, "%H:%M:%S", localtime(t));
    char **date = new char *[2];
    date[0] = year;
    date[1] = time;
    return date;
}

class Buffer
{
private:
    static vector<string> data; //тут храним данные
    string file_path;
    Buffer(){file_path = string(FILE_LOG);}
    Buffer(const Buffer &r){};
public:
    static Buffer &Instanse(){
        static Buffer instanse;
        return instanse;
    }
    void add(string line){      
    //добавляет строку в буффер. Если буфер переполнен, данные сбрасываются на диск
        data.push_back(line);
        if(data.size() > MAX_BUFFER_SIZE) {
            cout<<"Buffer unreached.";
            flush();
        }
    }
    
    void flush()
    //сбрасывает данные на диск
    {
        cout<<"Flushing\n";
        ofstream stream(file_path.c_str(), ios::app);
        for(vector<string>::iterator i = data.begin(); i < data.end(); i++){
            stream<<*i<<"\n";
        }
        stream.close();
        data.clear();
    }
    
    ~Buffer(){cout<<"OLALAL";flush();}
};

vector<string> Buffer::data;

class Log{
    string level;
    int code;
    
    int get_code_by_level(char *l);
    bool log_level_correct(char *l);
    
    Log(){set_log_level("INFO");};
public:
    static Log &Instanse(){
        static Log ins;
        return ins;
    }
    
    void set_log_level(char *l);
    
    void log(char *level, string message);
    void log(char *level, char *message){log(level, string(message));}
};

int Log::get_code_by_level(char *l){
    if(l == "ERROR")
        return 1;
    else if(l == "WARNING")
        return 2;
    else if(l == "INFO")
        return 3;
    else{
        cerr<<"Incorrect code level(in get_code_by_level)"<<endl;
        exit(-1);
    }
}

bool Log::log_level_correct(char *l){
    if(l != "INFO" and l!="WARNING" and l!="ERROR"){
        return false;
       exit(-1);
    }
    return true;
}


void Log::set_log_level(char *l){
    string temp(l);
    if(!log_level_correct(l)){
        cerr<<"Incorrect log_level."<<endl;
        exit(-1);
    }
    level = l;
    code = get_code_by_level(l);
}

void Log::log(char *level, string message){
    if(!log_level_correct(level)){
        cerr<<"Incorrect log_level."<<endl;
        exit(-1);
    }
    if(get_code_by_level(level)<=code){
        char **date = my_get_time();
        message = string("[") + string(date[0]) + string("]") + 
                string("[") + string(date[1]) + string("]") + 
                string("[") + string(level) + string("]") + 
                message;
        if(errno and code<3){
            message += string(" (errno message: ") + string(strerror(errno))
                    +string(")");
        }

        Buffer::Instanse().add(message);
    }
}

#endif



